package ca.etsmtl.log540.tp3;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

public class UTFServerNIO {

    public final int PORT = 1337;
    Selector selector = null;
    ServerSocketChannel serverChannel = null;
    ServerSocket serverSocket = null;

    public static void main(String[] args) throws IOException {
        new UTFServerNIO().run();
    }

    void run() throws IOException {

        InetSocketAddress address;
        try {
            serverChannel = ServerSocketChannel.open();
            serverChannel.configureBlocking(false);
            serverSocket = serverChannel.socket();
            address = new InetSocketAddress(PORT);
            serverSocket.bind(address);

            selector = Selector.open();
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);

            System.out.println("Server is running, send 'shutdown' command to terminate.");

            while (true) {
                if (selector.select() == 0) {
                    continue;
                }

                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

                while (keyIterator.hasNext()) {
                    SelectionKey key = keyIterator.next();

                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        SocketChannel client = server.accept();
                        client.configureBlocking(false);
                        client.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(100));

                    } else if (key.isReadable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer output = (ByteBuffer) key.attachment();
                        client.read(output);

                        String message = new String(output.array(), "UTF8").trim();

                        if (message.contains("shutdown")) {
                            CloseServer();
                            return;
                        }

                        System.out.println(message);

                        output.clear();
                        client.close();
                    }

                    keyIterator.remove();
                }
            }

        } catch (IOException ex) {
            Logger.getLogger(UTFServerNIO.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                IOUtil.close(selector);
                IOUtil.close(serverSocket);
                IOUtil.close(serverChannel);
            } catch (Exception e) {
                // do nothing - server failed
            }
        }
    }

    public void CloseServer() throws IOException {
        System.out.println("Recieved shutdown command, server terminated.");
        IOUtil.close(selector);
        IOUtil.close(serverSocket);
        IOUtil.close(serverChannel);
    }
}
